package com.itljm.cxrMarket.security;

import com.itljm.cxrMarket.filter.JwtAuthenticationFilter;
import com.itljm.cxrMarket.security.impl.AccessDeniedHandlerImpl;
import com.itljm.cxrMarket.security.impl.AuthenticationEntryPointImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

/**
 * @author ljm
 * @date 2024/11/1 16:56
 */
@Configuration//声明本类是一个配置类
@EnableMethodSecurity//开启方法级别认证
public class SecurityConfig {
    //做用户认证的服务
    @Autowired
    @Qualifier(value = "sys_user")   // Spring指定注入哪个类
    UserDetailsService userDetailsService;
    // 权限异常处理
    @Autowired
    AccessDeniedHandlerImpl accessDeniedHandler;
    // 权限异常处理
    @Autowired
    AuthenticationEntryPointImpl authenticationEntryPoint;
    // 自定义的jwt过滤器
    @Autowired
    JwtAuthenticationFilter jwtAuthenticationFilter;
    // 密码加密方式
    @Bean
    public PasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }

    // 权限认证提供者
    @Bean
    public AuthenticationProvider authenticationProvider(){
        DaoAuthenticationProvider authenticationProvider = new DaoAuthenticationProvider();
        //权限认证调用的service
        authenticationProvider.setUserDetailsService(userDetailsService);
        //声明加密方式
        authenticationProvider.setPasswordEncoder(passwordEncoder());

        return authenticationProvider;
    }

    // 获取认证管理器
    // 登录是执行一次AuthenticationManager，执行一次权限校验
    @Bean
    public AuthenticationManager authenticationManager(AuthenticationConfiguration configuration) throws Exception{
        return configuration.getAuthenticationManager();
    }

    // 做鉴权
    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
                // 禁用basic明文验证
                .httpBasic(Customizer.withDefaults())
                // 前后端分离架构不需要csrf保护
                .csrf(csrf -> csrf.disable())
                .authorizeHttpRequests(authorize -> authorize
                                // 允许所有OPTIONS请求
                                .requestMatchers(HttpMethod.OPTIONS, "/**").permitAll()
                                // 允许直接访问授权登录接口
                                .requestMatchers(HttpMethod.POST, "/sysUser/login").anonymous()
                                // 无需认证都能访问的地址
                                .requestMatchers("/jwt/refreshToken","product/getAllProducts","sysUser/register",
                                        "/wx/**","shoppingCart/**","orders/**","orderItem/**","merchants/my/**",
                                        "reviews/**","categories/**","product/getWxCategoryGoods","orders/count",
                                        "address/**","orders/getOrders","feedbackInfo/**","sysUser/infoByName",
                                        "sysUser/logout","sysUser/code","file/**").permitAll()
                                // 不需要鉴权能访问的地址
                                .requestMatchers("/file/**").permitAll()
                        // 其他所有接口必须有Authority信息，Authority在登录成功后的UserDetailsImpl对象中默认设置“ROLE_USER”
//                         .requestMatchers("/**").hasAnyAuthority("ROLE_USER")
                        // 其他所有接口需要登录认证才能访问
                         .anyRequest().authenticated()
                )
                // 默认登录页
                .formLogin(form-> form.disable())
                // 禁用默认登出页
                .logout(logout -> logout.disable())
                // 允许跨域请求
                .cors(Customizer.withDefaults())
                // 开启记住我功能
//                .rememberMe(rem->{rem.key("CXR_MARKET").rememberMeParameter("remember-me");})
                // 前后端分离是无状态的，不需要session了，直接禁用。
                .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
                // 添加权限认证提供者
                .authenticationProvider(authenticationProvider())
                // 添加jwt过滤器,放在UsernamePasswordAuthenticationFilter之前，保证jwt过滤器先执行
                .addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class)
                // 异常处理
                .exceptionHandling(exception -> exception.authenticationEntryPoint(authenticationEntryPoint).accessDeniedHandler(accessDeniedHandler));
        return http.build();
    }
}
